/**
 @file ctc_asw_ipmc.c

 @date 2020-06-15

 @version v1.0


*/

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_asw_common.h"
#include "ctc_ipmc.h"
#include "ctc_asw_ipmc.h"
#include "asw/include/drv_api.h"

/****************************************************************************
*
* Function
*
*****************************************************************************/
int32
ctc_asw_ipmc_add_group(uint8 lchip, ctc_ipmc_group_info_t* p_group)
{
    McTable_m      mc_fdb_key;
    uint32          cmd = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    CTC_PTR_VALID_CHECK(p_group);
    CTC_ASW_FID_RANGE_CHECK(p_group->address.ipv4.vrfid);
    CTC_L2_IP_IS_MCAST(p_group->address.ipv4.group_addr);
    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));

    CTC_API_LOCK(lchip);
    IPMC_MASK_IPV4_ADDR(p_group->address.ipv4.group_addr,p_group->group_ip_mask_len);
    hw_mac[1] = 0;
    hw_mac[0] = p_group->address.ipv4.group_addr;
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,p_group->address.ipv4.vrfid);
    SetMcTable(V,arlType_f,&mc_fdb_key,3);
    SetMcTable(V,portId_f,&mc_fdb_key,0);
    SetMcTable(V,state_f,&mc_fdb_key,1);
    SetMcTable(V,dmacFilter_f,&mc_fdb_key,0);
    SetMcTable(V,smacFilter_f,&mc_fdb_key,0);
    SetMcTable(V,stationMoved_f,&mc_fdb_key,0);
    SetMcTable(V,pendingLearn_f,&mc_fdb_key,0);
    SetMcTable(V,mstp_f,&mc_fdb_key,0);
    cmd = DRV_IOHA(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    CTC_API_UNLOCK(lchip);
    return ret;

}

int32
ctc_asw_ipmc_remove_group(uint8 lchip, ctc_ipmc_group_info_t* p_group)
{
    McTable_m      mc_fdb_key;
    uint32          cmd = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    CTC_PTR_VALID_CHECK(p_group);
    CTC_ASW_FID_RANGE_CHECK(p_group->address.ipv4.vrfid);
    CTC_L2_IP_IS_MCAST(p_group->address.ipv4.group_addr);

    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    CTC_API_LOCK(lchip);
    IPMC_MASK_IPV4_ADDR(p_group->address.ipv4.group_addr,p_group->group_ip_mask_len);
    hw_mac[1] = 0;
    hw_mac[0] = p_group->address.ipv4.group_addr;
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,p_group->address.ipv4.vrfid);
    SetMcTable(V,arlType_f,&mc_fdb_key,3);
    SetMcTable(V,state_f,&mc_fdb_key,1);
    cmd = DRV_IOHL(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    SetMcTable(V,state_f,&mc_fdb_key,0);
    cmd = DRV_IOHR(McTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    CTC_API_UNLOCK(lchip);
    return ret;
}

int32
ctc_asw_ipmc_get_group_info(uint8 lchip, ctc_ipmc_group_info_t* p_group)
{
    McTable_m      mc_fdb_key;
    L2mcMappingTable_m  mc_mapping_table;
    uint32          cmd = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    uint32          l2mc_index  = 0;
    uint8           linkagg_id = 0;
    CTC_PTR_VALID_CHECK(p_group);
    CTC_ASW_FID_RANGE_CHECK(p_group->address.ipv4.vrfid);
    CTC_L2_IP_IS_MCAST(p_group->address.ipv4.group_addr);

    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    sal_memset(&mc_mapping_table, 0, sizeof(L2mcMappingTable_m));

    CTC_API_LOCK(lchip);
    /*get group info*/
    IPMC_MASK_IPV4_ADDR(p_group->address.ipv4.group_addr,p_group->group_ip_mask_len);
    hw_mac[1] = 0;
    hw_mac[0] = p_group->address.ipv4.group_addr;
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,p_group->address.ipv4.vrfid);
    SetMcTable(V,arlType_f,&mc_fdb_key,3);
    SetMcTable(V,state_f,&mc_fdb_key,1);
    cmd = DRV_IOHL(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);

    /*get member info*/
    l2mc_index = GetMcTable(V,portId_f,&mc_fdb_key);
    cmd = DRV_IOR(L2mcMappingTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,l2mc_index,cmd,&mc_mapping_table);
    p_group->ipmc_member[0].port_bmp[0] = GetL2mcMappingTable(V,dstBitmap_f,&mc_mapping_table);
    linkagg_id = GetL2mcMappingTable(V,lagBitmap_f,&mc_mapping_table);
    p_group->ipmc_member[0].port_bmp[0] |= ((linkagg_id&0x7)<<CTC_ASW_MAX_PORT_NUM_PER_CHIP);
    p_group->ipmc_member[0].port_bmp[1] = linkagg_id>>3&0x3;
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_ipmc_add_member(uint8 lchip, ctc_ipmc_group_info_t* p_group)
{
    McTable_m            mc_fdb_key;
    L2mcMappingTable_m  mc_mapping_table;
    uint32          cmd = 0;
    uint32          l2mc_index  = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    uint8           linkagg_id = 0;
    CTC_PTR_VALID_CHECK(p_group);
    CTC_ASW_FID_RANGE_CHECK(p_group->address.ipv4.vrfid);
    CTC_L2_IP_IS_MCAST(p_group->address.ipv4.group_addr);

    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    sal_memset(&mc_mapping_table, 0, sizeof(L2mcMappingTable_m));

    CTC_API_LOCK(lchip);
    IPMC_MASK_IPV4_ADDR(p_group->address.ipv4.group_addr,p_group->group_ip_mask_len);
    hw_mac[1] = 0;
    hw_mac[0] = p_group->address.ipv4.group_addr;
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,p_group->address.ipv4.vrfid);
    SetMcTable(V,arlType_f,&mc_fdb_key,3);
    cmd = DRV_IOHL(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    l2mc_index = GetMcTable(V,portId_f,&mc_fdb_key);
    SetL2mcMappingTable(V,bypassEvt_f,&mc_mapping_table,1);
    SetL2mcMappingTable(V,bypassStp_f,&mc_mapping_table,0);
    linkagg_id = (((p_group->ipmc_member[0].port_bmp[1] & 0x3) << 3) | ((p_group->ipmc_member[0].port_bmp[0] >> CTC_ASW_MAX_PORT_NUM_PER_CHIP) & 0x7));
    SetL2mcMappingTable(V,lagBitmap_f,&mc_mapping_table,linkagg_id);
    p_group->ipmc_member[0].port_bmp[0] = (p_group->ipmc_member[0].port_bmp[0] & 0xFFFFFFF);
    SetL2mcMappingTable(V,dstBitmap_f,&mc_mapping_table,p_group->ipmc_member[0].port_bmp[0]);
    cmd = DRV_IOW(L2mcMappingTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,l2mc_index,cmd,&mc_mapping_table);

    CTC_API_UNLOCK(lchip);
    return ret;
}

int32
ctc_asw_ipmc_remove_member(uint8 lchip, ctc_ipmc_group_info_t* p_group)
{
    McTable_m            mc_fdb_key;
    L2mcMappingTable_m  mc_mapping_table;
    uint32          cmd  = 0;
    uint32          l2mc_index  = 0;
    uint32          value  = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    uint8           linkagg_id = 0;
    CTC_PTR_VALID_CHECK(p_group);
    CTC_ASW_FID_RANGE_CHECK(p_group->address.ipv4.vrfid);
    CTC_L2_IP_IS_MCAST(p_group->address.ipv4.group_addr);


    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    sal_memset(&mc_mapping_table, 0, sizeof(L2mcMappingTable_m));

    CTC_API_LOCK(lchip);
    IPMC_MASK_IPV4_ADDR(p_group->address.ipv4.group_addr,p_group->group_ip_mask_len);
    hw_mac[1] = 0;
    hw_mac[0] = p_group->address.ipv4.group_addr;
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,p_group->address.ipv4.vrfid);
    SetMcTable(V,arlType_f,&mc_fdb_key,3);
    cmd = DRV_IOHL(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    l2mc_index = GetMcTable(V,portId_f,&mc_fdb_key);
    cmd = DRV_IOR(L2mcMappingTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,l2mc_index,cmd,&mc_mapping_table);

    linkagg_id = GetL2mcMappingTable(V,lagBitmap_f,&mc_mapping_table);
    linkagg_id = ~(((p_group->ipmc_member[0].port_bmp[1] & 0x3) << 3) |((p_group->ipmc_member[0].port_bmp[0] >> CTC_ASW_MAX_PORT_NUM_PER_CHIP) & 0x7)) & linkagg_id;
    SetL2mcMappingTable(V,lagBitmap_f,&mc_mapping_table,linkagg_id);
    value = GetL2mcMappingTable(V,dstBitmap_f,&mc_mapping_table);
    value = (~(p_group->ipmc_member[0].port_bmp[0] & 0xFFFFFFF) & value);
    SetL2mcMappingTable(V,dstBitmap_f,&mc_mapping_table,value);

    cmd = DRV_IOW(L2mcMappingTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,l2mc_index,cmd,&mc_mapping_table);
    CTC_API_UNLOCK(lchip);
    return ret;

}

int32
ctc_asw_ipmc_init(uint8 lchip, void* ipmc_global_cfg)
{
    return CTC_E_NONE;
}

int32
ctc_asw_ipmc_deinit(uint8 lchip)
{
    return CTC_E_NONE;
}
